package it.antonio.ilpizze.db.core;

import it.antonio.ilpizze.db.DbException;
import it.antonio.ilpizze.db.Id;
import it.antonio.ilpizze.db.Ids;
import it.antonio.ilpizze.db.Record;
import it.antonio.ilpizze.db.Records;
import it.antonio.ilpizze.db.RecordsAndIds;
import it.antonio.ilpizze.db.statistics.Statistics;
import it.antonio.ilpizze.func.ComputeIterator;
import it.antonio.ilpizze.func.Pair;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class RecordFileRecords implements Records {

	private MonitorManager monitorManager;
	private Iterator<Pair<Id,Record>> it;
	
	private boolean iterating = false;
	
	public RecordFileRecords(MonitorManager monitorManager, Iterator<Pair<Id,Record>> it) {
		this.monitorManager = monitorManager;
		this.it = it;
	}
	
	@Override
	public Iterator<Record> iterator() {
		checkAlreadyIterated();
		return new ComputeIterator<Record>() {

			@Override
			protected Record computeNext() {
				iterating = true;
				if(it.hasNext()){
					return it.next().second();
				}
				return finished();
			}
		};
	}
	@Override
	public Record first() {
		checkAlreadyIterated();
		Record first = null;
		if(it.hasNext()){
			first = it.next().second();
		}
		endIteration();
		return first;
	}
	
	@Override
	public List<Record> list() {
		checkAlreadyIterated();
		List<Record> records = new ArrayList<Record>();
		for(Record record: this){
			records.add(record);
		}
		endIteration();
		return records;
	}

	@Override
	public List<Record> list(int num) {
		checkAlreadyIterated();
		List<Record> records = new ArrayList<Record>();
		int count = 0;
		for(Record record: this){
			records.add(record);
			count++;
			if(count == num) return records;
		}
		endIteration();
		return records;
	}
	
	@Override
	public void endIteration() {
		monitorManager.stop(Statistics.RecordLoad);
	}
	
	@Override
	public Ids ids() {
		checkAlreadyIterated();
		return new Ids() {

			@Override
			public Id first() {
				checkAlreadyIterated();
				if(it.hasNext()){
					return it.next().first();
				}
				endIteration();
				return null;
			}

			@Override
			public List<Id> list() {
				checkAlreadyIterated();
				List<Id> ids = new ArrayList<Id>();
				for(Id id: this){
					ids.add(id);
				}
				endIteration();
				return ids;
			}

			@Override
			public List<Id> list(int num) {
				checkAlreadyIterated();
				List<Id> ids = new ArrayList<Id>();
				int count = 0;
				for(Id id: this){
					ids.add(id);
					count++;
					if(count == num) return ids;
				}
				endIteration();
				return ids;
			}

			@Override
			public Iterator<Id> iterator() {
				checkAlreadyIterated();
				return new ComputeIterator<Id>() {

					@Override
					protected Id computeNext() {
						iterating = true;
						if(it.hasNext()){
							return it.next().first();
						}
						return finished();
					}
				};
			}
			
			@Override
			public void endIteration() {
				monitorManager.stop(Statistics.RecordLoad);
			}
		};
	}

	@Override
	public RecordsAndIds recordAndIds() {
		checkAlreadyIterated();
		return new RecordsAndIds() {

			@Override
			public Pair<Id, Record> first() {
				checkAlreadyIterated();
				if(it.hasNext()){
					return it.next();
				}
				endIteration();
				return null;
			}

			@Override
			public List<Pair<Id, Record>> list() {
				checkAlreadyIterated();
				List<Pair<Id,Record>> pairs = new ArrayList<Pair<Id,Record>>();
				for(Pair<Id,Record> pair: this){
					pairs.add(pair);
				}
				endIteration();
				return pairs;
			}

			@Override
			public List<Pair<Id, Record>> list(int num) {
				checkAlreadyIterated();
				List<Pair<Id,Record>> pairs = new ArrayList<Pair<Id,Record>>();
				int count = 0;
				for(Pair<Id,Record> pair: this){
					pairs.add(pair);
					count++;
					if(count == num) return pairs;
				}
				endIteration();
				return pairs;
			}

			@Override
			public Iterator<Pair<Id, Record>> iterator() {
				checkAlreadyIterated();
				return new ComputeIterator<Pair<Id, Record>>() {

					@Override
					protected Pair<Id, Record> computeNext() {
						iterating = true;
						if(it.hasNext()){
							return it.next();
						}
						return finished();
					}
				};
			}
			@Override
			public void endIteration() {
				monitorManager.stop(Statistics.RecordLoad);
			}
			
		};
	}

	private void checkAlreadyIterated(){
		if(iterating == true) throw new DbException("Iterator started: RecordLoad again");
	}
}